<!DOCTYPE html>

<html>
<head>
<meta charset="utf-8">
<title>D3 Test</title>
<script type="text/javascript" src="d3/d3.js"></script>
<script type="text/javascript" src="d3/crossfilter.min.js"></script>

<style type="text/css">
@import url(d3/style.css);

#chart {
	height: 600 px;
	width: 960 px;
}

.segment {
	fill-opacity: 1;
	stroke: #000;
	stroke-opacity: .3;
	shape-rendering: crispEdges;
}

.segment text {
	pointer-events: none;
	text-shadow: 0 1px 0 #fff;
}

.axis path,.axis line {
	fill: none;
	stroke: #000;
	shape-rendering: crispEdges;
}

.axis text {
	font: 10px sans-serif;
}

.link {
	fill-opacity: .8;
	shape-rendering: crispEdges;
	stroke-opacity: .8;
}

.link:hover {
	stroke-opacity: .4;
	opacity: .4
}

.brush .extent {
	stroke: #fff;
	fill-opacity: .125;
	shape-rendering: crispEdges;
}
</style>

</head>
<body>
	<header>
		<!--  aside>August 31, 2012</aside>
		<a href="../" rel="author">Dakuo WANG</a><br/>
		<a href="../" rel="author">Jingwen ZHANG</a-->
	</header>

	<h1>History Flow Diagrams</h1>
	
	<p></p>
	
	<div id="chart"></div>
	
	<p class="attribution">
		Source:
		<!-- a
			href="http://www.decc.gov.uk/en/content/cms/tackling/2050/calculator_on/calculator_on.aspx">Department
			of Energy & Climate Change</a>, <a href="http://tamc.github.com/Sankey/">Tom
			Counsell</a -->
		.

		<aside>
			History Flow diagrams are closely related to <a
				href="http://en.wikipedia.org/wiki/IBM_History_Flow_tool">IBM
				history flow</a>, which invented by MartinWattenberg and Fernanda
			Viegas.
		</aside>
	</p>
	<footer>
		<aside>August 31, 2012</aside>
		<a href="../" rel="author">Jingwen ZHANG</a><br /> 
		<a href="../" rel="author">Dakuo WANG</a>
	</footer>

	<script type="text/javascript">
		// Your beautiful D3 code will go here

		var width = 960, height = 600, color = d3.scale.category10(), margin = {
			top : 20,
			right : 10,
			bottom : 10,
			left : 10
		};
		var formatTime = d3.time.format("%B %d, $I:%M %p");

		var svg = d3.select("#chart").append("svg").attr("width",
				width + margin.left + margin.right).attr("height",
				height + margin.top + margin.bottom);

		/* Like d3.time.format, but faster.
		function parseTime(d) {
			return new Date(d.substring(0, 4), d.substring(5, 7) - 1, d
					.substring(8, 10), d.substring(11, 13), d.substring(14, 16));
		}
		*/
		d3.json("revisions.json",
						function(dataset) {

							var revisions = dataset.revisions;

							/* For crossfilter */
							var revisionsDataset = crossfilter(revisions),
							//time = revisions.dimension(function(d) { return d3.time.day(parseTime(d.time)); }),
							revisionByOrder = revisionsDataset
									.dimension(function(d, i) {
										return i;
									}),
							//revisionByOrder.top(4);
							revisionGroupByOrder = revisionByOrder.group(), brush = d3.svg
									.brush();
							/* END of Crossfilter*/

							var authors = dataset.authors;
							var segments = dataset.segments;
							var barPadding = width / revisions.length / 2;

							var xScale = d3.scale.ordinal().domain(
									d3.range(revisions.length))
									.rangeRoundBands([ 0, width ], 0.5);

							var yScale = d3.scale.linear().domain(
									[ 0, d3.max(revisions, function(d) {
										return d.revisionLength;
									}) ]).range([ 0, height ]);

							var xAxis = d3.svg.axis().scale(xScale).orient(
									"top").ticks(revisions.length);

							//var yAxis = d3.svg.axis().scale(yScale).orient("left").ticks(10);


							var groups = svg.selectAll("rectGroup").data(revisions)
									.enter().append("g")
									.attr("class","rectGroup")
									.attr(
											"transform",
											"translate(" + margin.left + ","
													+ margin.top + ")");

							
							var revisionIndex = -1;
							var accumulateSegLength = 0;
							var displayGroups = function(groups, start, end){
								
							return	groups
								.filter(function(d,i){return i>=start&&i<=end;})
									.selectAll("rect")
									.data(function(d) {
										if(d.segments.length != 0)
											return d.segments;
										else
											return [-1];
									})
									.enter()
									.append("rect")
									.attr("class", "segment")
									.attr("x", function(d, i) {
										if (i == 0)
											revisionIndex++;
										return xScale(revisionIndex);
									})
									.attr(
											"y",
											function(d, i) {
												if (i == 0) {
													if(d==-1)
														return yScale(0);
													else{
														accumulateSegLength = segments[d].segmentLength;
														return yScale(accumulateSegLength
															- segments[d].segmentLength);
													}
												} else {
													accumulateSegLength += segments[d].segmentLength;
													return yScale(accumulateSegLength
															- segments[d].segmentLength);
												}
											})
									.attr("width", xScale.rangeBand())
									.attr("height",function(d) {
												if(d==-1)
													return 0;
												else
													return yScale(segments[d].segmentLength);
											})
									.attr("fill", function(d, i) {
										if(d != -1)
											return color(segments[d].authorId)
									})
									.on("mouseover", function(d) {
										if(d!=-1)
											d3.select(this).attr("title", segments[d].content);
									})
									.on("click",function(){
										start = end +1;
										end = end+10;
										displayGroups(groups,start,end);
										displayLinks(linkGroups,start-1,end-1);
									});
							}
							
							displayGroups(groups,0,10);
							

							//===============================
							var link = [], preSegment = [];
							for ( var j = 0; j < revisions.length - 1; j++) {
								link[j] = [];//link[j] represent the link between revision j and j+1
								preSegment = revisions[j].segments; //revision j segments
								newSegment = revisions[j + 1].segments; //revision j+1 segments
								//iterate revision j+1 segments to find father segment (segmentId) or it own(-1) in the previous revision 
								for ( var k = 0; k < newSegment.length; k++) {
									if (segments[newSegment[k]].fatherSegmentIndex < 0) {
										preIndex = preSegment
												.indexOf(newSegment[k]);
										if (preIndex != -1){
											link[j].push([
													preSegment[preIndex],
													newSegment[k] ]);
										}
										else{
											//No link
										}
									} else {
										preIndex = preSegment
												.indexOf(segments[newSegment[k]].fatherSegmentIndex);
										if (preIndex != -1){
											link[j].push([
													preSegment[preIndex],
													newSegment[k] ]);
										}
										else{

											preIndex = preSegment
											.indexOf(newSegment[k]);
											if (preIndex != -1){
												link[j].push([
													preSegment[preIndex],
													newSegment[k] ]);
											}
											else{
												alert("link compute error"+preIndex+" "+segments[newSegment[k]]);
											}
										}
									}
									
									}
									if(link[j].length ==0){
										link[j].push([-1,-1]);
								}

							}
							

							var linkGroups = svg
									.selectAll("linkGroup")
									.data(link)
									.enter()
									.append("g")
									.attr("class","linkGroup")
									.attr(
											"transform",
											"translate("
													+ (margin.left + barPadding)
													+ "," + margin.top + ")");
							
							var linkRevisionIndex = -1;
							var displayLinks = function(linkGroups, start1, end1){
								
								return linkGroups
									.filter(function(d,i){return i>=start1 && i<=end1;})
									.selectAll("link")
									.data(function(d) {
										return d;
									})
									.enter()
									.append("path")
									.attr("class", "link")
									.attr(
											"d",
											function(d, i) {

												if (i == 0 ) {
													linkRevisionIndex++;
													accumulateSegLength1 = 0;
													accumulateSegLength2 = 0;
												}

												if (d[1] == -1) {
													return "";
												} else {
													
													x0 = xScale(linkRevisionIndex);
													var tempSegments1 = revisions[linkRevisionIndex].segments;
													var tempSegments2 = revisions[linkRevisionIndex + 1].segments;

													var index1 = tempSegments1.indexOf(d[0]);
													var index2 = tempSegments2.indexOf(d[1]);

													var accumulateSegLength1 = 0, accumulateSegLength2 = 0;

													for ( var q = 0; q < index1; q++) {
														accumulateSegLength1 += segments[tempSegments1[q]].segmentLength;
													}
													for ( var q = 0; q < index2; q++) {
														accumulateSegLength2 += segments[tempSegments2[q]].segmentLength;
													}
													
													if(d[1]==d[0]){
														y0 = yScale(accumulateSegLength1);
													}
													else{
														y0 = yScale(accumulateSegLength1+segments[d[1]].offsetInFatherSegment);
													}
													y1 = yScale(accumulateSegLength2);

													x1 = x0 + xScale.rangeBand();
													dy = yScale(segments[d[1]].segmentLength);

													return "M " + x0 + "," + y0
															+ " " + x0 + ","
															+ (y0 + dy) + " "
															+ x1 + ","
															+ (y1 + dy) + " "
															+ x1 + "," + y1
															+ "Z";
												}

											})
									.attr("fill", function(d, i) {
												if(d[1]!=-1)
													return color(segments[d[1]].authorId)})
									.attr("opacity", 0.8)
									;
									
								}
							

							displayLinks(linkGroups,0,9);
							//===============================*/

							svg.append("g").attr("class", "axis").attr(
									"transform",
									"translate(" + margin.left + ","
											+ margin.top + ")").call(xAxis);

							/*
							svg.append("g")
							.attr("class","axis")
							.attr("transform","translate(50,0)")
							.call(yAxis);
							 */

							/*
							var sortBars = function() {
							    svg.selectAll("rect")
							       .sort(function(a, b) {
							    	   return d3.ascending(a.revisionLength, b.revisionLength);
							            })
							       .transition()
							       .delay(function(d,i){return i*50;})
							       .duration(1000)
							       .attr("x", function(d, i) {
							                    return xScale(i);
							       });
							    };
							 */

						});
	</script>
</body>
</html>
